function RDFaViewer(data, fileName, serverURL) {
    this.gridView = undefined;
    this.treeView = undefined;
    this.settingData = {
        fileName : fileName,
        serverURL : serverURL
    }
    this.data = data;
    this.initUI();
}

RDFaViewer.prototype.initUI = function() {
    // create the Grid
    this.gridView = new Ext.grid.GridPanel({
        title : 'Grid View',
        viewConfig : {
            forceFit : true
        },
        columns : [ {
            id : 'index',
            header : 'No.',
            width : 25,
            sortable : true,
            dataIndex : 'index'
        }, {
            id : 'object',
            header : 'Object',
            width : 250,
            sortable : true,
            dataIndex : 'object'
        }, {
            header : 'Attribute',
            width : 75,
            sortable : true,
            dataIndex : 'attribute'
        }, {
            header : 'Value',
            width : 250,
            sortable : true,
            dataIndex : 'value'
        } ],
        stripeRows : true,
        autoExpandColumn : 'object',
        stateful : true,
        stateId : 'grid'
    });

    this.gridView.store = new Ext.data.ArrayStore({
        fields : [ {
            name : 'index'
        }, {
            name : 'object'
        }, {
            name : 'attribute'
        }, {
            name : 'value'
        } ]
    });

    this.treeView = new Ext.ux.tree.TreeGrid({
        title : 'Tree View',
        enableDD : true,
        columns : [ {
            header : 'Triple',
            dataIndex : 'triple',
            width : 420
        }, {
            header : 'RDF attribute',
            width : 100,
            sortable : false,
            dataIndex : 'attribute'
        }, {
            header : 'Defined Attribute',
            width : 100,
            sortable : false,
            dataIndex : 'tag'
        } ],

        loader : new Ext.ux.tree.TreeGridLoader()
    });

    var form = new Ext.FormPanel({
        labelWidth : 120,
        frame : true,
        bodyStyle : 'padding:10px 10px 10px 10px',
        defaults : {
            width : 250
        },
        defaultType : 'textfield',
        items : [ {
            fieldLabel : 'File name',
            name : 'fileName',
            value : this.settingData.fileName
        }, {
            fieldLabel : 'Server URL',
            name : 'serverURL',
            value : this.settingData.serverURL
        } ]
    });

    var win = new Ext.Window({
        title : 'Setting',
        layout : 'fit',
        width : 500,
        height : 145,
        closeAction : 'hide',
        maximizable : false,
        items : [ form ],
        buttons : [ {
            text : 'Save',
            scope : this,
            handler : function() {
                this.settingData = form.getForm().getValues();
                chrome.extension.getBackgroundPage().rdfaSettingData = form.getForm().getValues();
                win[win.closeAction]();
            }
        }, {
            text : 'Close',
            scope : this,
            handler : function() {
                win[win.closeAction]();
            }
        } ]
    });
    var settingPanel = new Ext.Button({
        text : 'Setting',
        width : 50,
        height : 27,
        renderTo : 'setting-panel',
        scope : this,
        style : 'position:absolute; top:0px; right:0px;',
        handler : function() {
            win.show(this);
        }
    });

    new Ext.Viewport({
        layout : 'border',
        items : [
                {
                    region : 'center',
                    title : 'RDFa Viewer',
                    iconCls : 'rdfa-viewer-window-ico',
                    layout : 'fit',
                    items : [ {
                        xtype : 'tabpanel',
                        title : 'RDFa Viewer',
                        iconCls : 'rdfa-viewer-window-ico',
                        activeTab : 0,
                        border : false,
                        items : [ this.gridView, this.treeView ]
                    } ]
                },
                {
                    region : 'south',
                    height : 38,
                    frame : true,
                    layout : 'hbox',
                    defaults : {
                        xtype : 'button',
                        height : 25,
                        width : 100,
                        style : 'padding-right:4px'
                    },
                    items : [
                            {
                                text : 'Save',
                                handler : function() {
                                    var renderer = new JsonRenderer();
                                    if (!FileHelper.createFile(this.settingData.fileName, renderer.encode(
                                            this.prepareData(this.data)).toArray())) {
                                        Ext.Msg.alert('Status', 'Save fail. Please try again!');
                                    }
                                },
                                scope : this
                            },
                            {
                                text : 'Submit',
                                handler : function() {
                                    Ext.Ajax.request({
                                        url : this.settingData.serverURL,
                                        success : function() {
                                            Ext.Msg.alert('Success', 'Submit to "' + this.settingData.serverURL
                                                    + '" success');
                                        },
                                        failure : function() {
                                            Ext.Msg.alert('Error', 'Submit to "' + this.settingData.serverURL
                                                    + '" fail');
                                        },
                                        scope : this,
                                        params : {
                                            data : Ext.encode(this.prepareData(this.data))
                                        }
                                    });

                                },
                                scope : this
                            } ]
                } ]
    });
};

RDFaViewer.prototype.loadData = function(data) {
    this.data = data;
    this.gridViewData = this.createGridViewData(data);
    this.treeViewData = this.createTreeViewData(data);
    this.refresh();
};

RDFaViewer.prototype.createGridViewData = function(data) {
    var result = [];
    Ext.each(data, function(triple, index) {
        result.push([ index, triple.subject.value, triple.predicate.value, triple.object.value ]);
    });
    return result;
}

RDFaViewer.prototype.createTreeViewData = function(data) {
    // Prepare tree grid data
    var j = new Ext.util.MixedCollection();

    Ext.each(data, function(triple) {
        if (j.get(triple.subject.value)) {
            j.get(triple.subject.value).children.push({
                text : triple.predicate.value,
                draggable : false,
                triple : triple.predicate.value,
                attribute : 'Predicate',
                tag : triple.predicate.tag,
                children : [ {
                    text : triple.object.value,
                    triple : triple.object.value,
                    attribute : 'Object',
                    tag : triple.object.tag,
                    leaf : true
                } ]
            });
        } else {
            j.add(triple.subject.value, {
                text : triple.subject.value,
                draggable : false,
                triple : triple.subject.value,
                attribute : 'Subject',
                tag : triple.subject.tag,
                children : []
            });
        }
    });
    return j.getRange();
}

RDFaViewer.prototype.refresh = function() {
    this.gridView.store.loadData(this.gridViewData);
    this.gridView.view.refresh();

    // set the root node
    var root = new Ext.tree.AsyncTreeNode({
        text : 'Root',
        draggable : false,
        id : 'source',
        children : this.treeViewData
    });

    this.treeView.setRootNode(root);
};

RDFaViewer.prototype.prepareData = function(data) {
    var rs = [];
    for ( var i = 0; i < data.length; i++) {
        rs.push({
            subject : data[i].subject.value,
            predicate : data[i].predicate.value,
            object : data[i].object.value
        });
    }
    return rs;
}